/*
 * NetWorkMain.cpp
 *
 *  Created on: 2017年5月25日
 *      Author: orange
 */

#include "NetWorkMain.h"

#include <arpa/inet.h>
#include <asm-generic/errno-base.h>
#include <openssl/rc4.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include <sstream>
#include <utility>
#include <time.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>

#include "../public/cuckoohash_map.hh"
#include "../public/event/ClientQuitJuzEvent.h"
#include "../public/event/OnCommandJuzEvent.h"
#include "../public/event/OnDisableJuzEvent.h"
#include "../public/event/OnEnableJuzEvent.h"
#include "../public/event/TaskJuzEvent.h"
#include "../public/event/ThreadJuzEvent.h"
#include "../public/event/AskEncryptionJuzEvent.h"
#include "../public/event/TcpCheckJuzEvent.h"

using namespace std;

const int NetWorkMain::MAXEPOLLSIZE = 99999; //epoll最大句柄数
const int NetWorkMain::MAXLINE = 2048;//监听最大数
const int NetWorkMain::RECVTHREADNUM = 30;//接受服务端
const int NetWorkMain::MPORT = 10087;//服务端
const int NetWorkMain::SENDTHREADNUM = 30;//发送
const int NetWorkMain::TCPCHECKTIME = 4;//tcp 密钥时间检测
const int NetWorkMain::UNITEVERMCSERVER = 2000;//mc插件服务器版本
const int NetWorkMain::UNITEVERMANDROID = 2001;//android 版本

static char g_keyDefault[32] = "547396767999885"; //默认ｋｅｙ
static int g_Serverlistenfd = -1; //服务器的监听fd

//接受验证
static Juz_Socket_Validation g_socketVaRecv[] = {
		Juz_Socket_Validation(0x01,0x01), //密钥配对
		Juz_Socket_Validation(0x01,0x02),//mc服务器登录
		Juz_Socket_Validation(0x01,0x03),//android 客户端登录
		Juz_Socket_Validation(0x01,0x04),//mc服务器 返回 android客户端账号（登录）
		Juz_Socket_Validation(0x01,0x05),//android 聊天信息
		Juz_Socket_Validation(0x01,0x06),//mc服务器 聊天信息
		Juz_Socket_Validation(0x02,0x01),//mc服务器 同步在线人数
};

Plugin *loadSoPlugin()
{
	return NetWorkMain::getInstance();
}

int
socket_set_keepalive (int fd)
{
  int ret, error, flag, alive, idle, cnt, intv;

  /* Set: use keepalive on fd */
  alive = 1;
  if (setsockopt
      (fd, SOL_SOCKET, SO_KEEPALIVE, &alive,
       sizeof alive) != 0)
    {
      return -1;
    }

  /* 8秒钟无数据，触发保活机制，发送保活包 */
  idle = 8;
  if (setsockopt (fd, SOL_TCP, TCP_KEEPIDLE, &idle, sizeof idle) != 0)
    {
      return -1;
    }

  /* 如果没有收到回应，则５秒钟后重发保活包 */
  intv = 4;
  if (setsockopt (fd, SOL_TCP, TCP_KEEPINTVL, &intv, sizeof intv) != 0)
    {
      return -1;
    }

  /* 连续３次没收到保活包，视为连接失效 */
  cnt = 3;
  if (setsockopt (fd, SOL_TCP, TCP_KEEPCNT, &cnt, sizeof cnt) != 0)
    {
      return -1;
    }

  return 0;
}

////////////////////////////////////////////////////////////const

NetWorkMain * NetWorkMain::mNetWorkMain = NULL;
int  NetWorkMain::mEpollFd = -1;

char* NetWorkMain::randKey(char *str,int len)
{
    int i = 0;
    for(i=0;i<len;++i)
    {
         switch((rand()%3))
         {
         case 1:
        	 str[i]='A'+rand()%26;
        	 break;
        case 2:
        	str[i]='a'+rand()%26;
        	break;
        default:
        	str[i]='0'+rand()%10;
        	break;
         }
    }
    return str;
}

void NetWorkMain::OnDisable() {
	//销毁
	JuzLog::LogStr("开始关闭网络资源!");

	if(g_Serverlistenfd != -1)
	{
		close(g_Serverlistenfd);
	}
	if(mEpollFd != -1)
	{
		close(mEpollFd);
	}
	sem_destroy(recv_sem);
	sem_destroy(send_sem);

	//关闭　客户端
	auto  lt = mAllClientInfo.lock_table();
    for (const auto &it : lt) {
    	close(it.first);
    }
    lt.unlock();
}



NetWorkMain* NetWorkMain::getInstance() {
	if(mNetWorkMain == NULL)
	{
		mNetWorkMain = new NetWorkMain();
	}
	return mNetWorkMain;
}

NetWorkMain::NetWorkMain() {

	cout<<"new NetWorkMain"<<endl;
	JuzLog::Init(this);

	recv_sem = new sem_t;
	send_sem = new sem_t;
	sem_init(recv_sem, 0, 0);
	sem_init(send_sem, 0, 0);
}

NetWorkMain::~NetWorkMain() {
	OnDisable();
}

void NetWorkMain::bindFinsh() {
	registeredEvent(OnEnableJuzEvent::mEventName,10);
	registeredEvent(OnDisableJuzEvent::mEventName,10);
	registeredEvent(ClientQuitJuzEvent::mEventName,1);
	registeredEvent(OnCommandJuzEvent::mEventName,1);
	registeredEvent(SendSocketJuzEvent::mEventName,1);

	registeredEvent(AskEncryptionJuzEvent::mEventName,10);//别的模块询问
	registeredEvent(TcpCheckJuzEvent::mEventName,10);

}

void NetWorkMain::eventListen(JuzEvent* event) {
		string evName = event->mEventName;

		JuzLog::LogA(3,"NetWorkMain::eventListen:%s",event->mEventName);

		if(evName == OnEnableJuzEvent::mEventName)
		{
			OnEnable();
		}
		else if(evName == OnDisableJuzEvent::mEventName)
		{
			OnDisable();
		}
		else if(evName == ClientQuitJuzEvent::mEventName)
		{
			//cout<<"进入　ClientQuitJuzEvent"<<endl;
			ClientQuitJuzEvent *clEv = (ClientQuitJuzEvent*)event;
			clientQuit(clEv);
		}
		else if(evName == OnCommandJuzEvent::mEventName)
		{
			OnCommand((OnCommandJuzEvent*)event);
		}
		else if(evName == SendSocketJuzEvent::mEventName)
		{
			SendSocketJuzEvent *sendEv = (SendSocketJuzEvent*)event;
			sendData(sendEv);
		}
		else if(evName == AskEncryptionJuzEvent::mEventName)
		{
			AskEncryptionJuzEvent *askEv = (AskEncryptionJuzEvent*)event;
			int nfd = askEv->getNfd();
			bool isEn = false;//没加密
			mAllClientInfo.find_fn(nfd,[&](const JUZ_TBB_DATA& JuzTbbData){
				JUZ_EPOLL_CLIEN *JuzSocketInfo = NULL;
				JuzSocketInfo = JuzTbbData.mTo;
				isEn = JuzSocketInfo->mIsencrypt;
			});
			askEv->setIsYes(isEn);
		}
		else if(evName == TcpCheckJuzEvent::mEventName)
		{
			TcpCheckJuzEvent *tcpEv = (TcpCheckJuzEvent*)event;
			if(tcpEv->getState() == 1)
			{
				int *nTime = new int;
				*nTime = TCPCHECKTIME;
				mCheckList.insert(tcpEv->getFd(),nTime);
			}
		}
}
void NetWorkMain::sendData(SendSocketJuzEvent *sendEv)
{
	if(sendEv != NULL)
	{
		bool isSend = false;

		int nSocketfd = sendEv->getNfd();
		char key[32];
		memset(key,0,sizeof(key));
		JUZSENDINFO sendInfo;

		mAllClientInfo.find_fn(nSocketfd,[&](const JUZ_TBB_DATA& JuzTbbData){
			JUZ_EPOLL_CLIEN *JuzSocketInfo = NULL;
			JuzSocketInfo = JuzTbbData.mTo;

			if(JuzSocketInfo != NULL)
			{
				isSend = true;
				//增加信号 与 加到列表
				if(JuzSocketInfo->mIsencrypt) //如果有加密 使用
				{
					strcpy(key,JuzSocketInfo->mKey);
				}
				else
				{
					strcpy(key,g_keyDefault);
				}
				uuid_copy(sendInfo.uu,JuzSocketInfo->uu);
			}
		});

		if(isSend)
		{
			sendEv->setKey(key);
			sendEv->setRcvEn(NetWorkMain::RC4_SOCKET);
			sendEv->setEncryption();
			sendInfo.event = sendEv;

			if(mSendList.enqueue(sendInfo))
			{
				sem_post(send_sem);
			}
			else
			{
				isSend = false;
			}
		}

		if(!isSend)
		{
			sendEv->finsh();
			sendEv->setDisable(true); //销毁这个事件
		}
	}
}
//初始化
void NetWorkMain::OnEnable() {
	srand(time(NULL));
	InitSocket();
}
void NetWorkMain::InitSocket() {

	JuzLog::LogStr("初始化　服务端网络!");
	signal(SIGPIPE,SIG_IGN);//这里忽略掉这个信号　否则收到这个系统默认终止进程

	struct sockaddr_in servaddr, cliaddr;
	bzero(&servaddr, sizeof(servaddr));
	bzero(&cliaddr, sizeof(cliaddr));

	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(NetWorkMain::MPORT);
	g_Serverlistenfd = socket(AF_INET, SOCK_STREAM, 0);
	if(g_Serverlistenfd == -1)
	{
		JuzLog::LogStr("服务端　socket　失败!");
		return ;
	}

	if(bind(g_Serverlistenfd, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) == -1)
	{
		JuzLog::LogStr("服务端　bind　失败!");
	    return ;
	}

    if (listen(g_Serverlistenfd, NetWorkMain::MAXLINE) == -1)
    {
    	JuzLog::LogStr("服务端　listen　失败!");
        return ;
    }
    //使用 epoll 监听事件
    mEpollFd = epoll_create(MAXEPOLLSIZE);

    //启动 epoll监控线程
    {
    	for(int i = 0 ; i < 2 ; i ++)
    	{
    	       ThreadJuzEvent threadEpollWait("epoll wait任务线程");
    	        threadEpollWait.setTask(NetWorkMain::socketWaitData);
    	        sendEvent(&threadEpollWait); //发送事件出去
    	}
    }

    //启动 接受线程
    for(int i = 0 ; i < RECVTHREADNUM ; i ++)
    {
        ThreadJuzEvent threadEpollRecv("recv数据接受线程");
        threadEpollRecv.setTask(NetWorkMain::socketRecv);
        sendEvent(&threadEpollRecv); //发送事件出去
    }

    {
        //开始接受客户端连接
        ThreadJuzEvent threadAccept("接收客户线程");
        threadAccept.setTask(NetWorkMain::socketJuzAccept);
        threadAccept.setArgs((void*)&g_Serverlistenfd);
        sendEvent(&threadAccept); //发送事件出去
    }
    {
    	//tcp 僵尸连接检查
        ThreadJuzEvent threadTcpCheck("TCP检查线程");
        threadTcpCheck.setTask(NetWorkMain::socketTcpCheck);
        sendEvent(&threadTcpCheck); //发送事件出去
    }

    //发送线程
    for(int i = 0 ; i < SENDTHREADNUM ; i++)
    {
        ThreadJuzEvent threadEpollSend("send线程");
        threadEpollSend.setTask(NetWorkMain::sendSocketInfo);
        sendEvent(&threadEpollSend); //发送事件出去
    }

    JuzLog::LogStr("ne 线程开启完毕!");
    cout<<"socket　成功!"<<endl;
}
void* NetWorkMain::socketTcpCheck(void *args)
{
	NetWorkMain *ne = NetWorkMain::getInstance();
	list<int> delListTcp;
	//检查僵尸进程
	while(true)
	{
		sleep(1);
		delListTcp.clear();

		auto  lt = ne->mCheckList.lock_table();
	    for (const auto &it : lt) {
	    	int nfd = it.first;
	    	int *nTime = it.second;
	    	*nTime = *nTime - 1;

	    	if((*nTime) <= 0)
	    	{
	    		//关掉此链接
	    		delListTcp.push_back(nfd);
	    	}
	    }
	    lt.unlock();

	    //遍历list
	    list<int>::iterator list_it;
	    for(list_it = delListTcp.begin();list_it != delListTcp.end();list_it++)
	    {
	    	int fd = *list_it;
	    	ne->mCheckList.erase_fn(fd,[](int* &time){
	    		delete time;
	    		return true;
	    	});

	    	//删掉主要的
	    	ne->mAllClientInfo.erase_fn(fd,[&](JUZ_TBB_DATA & JuzTbbData){
	    		JUZ_EPOLL_CLIEN *JuzSocketInfo = NULL;
	    		JuzSocketInfo = JuzTbbData.mTo;

	    		if(JuzSocketInfo != NULL)
	    		{
	    			if(!JuzSocketInfo->mIsencrypt)
	    			{
	    				//没加密
						JuzLog::LogA(4,"tcp关掉链接 fd:%d",fd);

	    				delete JuzSocketInfo;
	    				JuzTbbData.mTo = NULL;
	    				close(fd);//关掉客户端
	    				return true;
	    			}
	    		}
	    		return false;
	    	});
	    }
	}
	return NULL;
}
void* NetWorkMain::sendSocketInfo(void *args)
{
	NetWorkMain *netMain = NetWorkMain::getInstance();
	while(true)
	{
		sem_wait(netMain->send_sem);
		JUZSENDINFO juzSendInfo;
		if(netMain->mSendList.try_dequeue(juzSendInfo))  //只要弹出来了 就一定要处理完 处理不完直接丢弃数据
		{
			SendSocketJuzEvent *sendEv = (SendSocketJuzEvent*)juzSendInfo.event;
			int nSocketFD = sendEv->getNfd();
			int nFinshState = 0;

			bool isMutex = false;
			bool isSendState = false;

			auto findStatePro = [&](const JUZ_TBB_DATA& JuzTbbData){
				JUZ_EPOLL_CLIEN *JuzSocketInfo = NULL;
				JuzSocketInfo = JuzTbbData.mTo;

				if(JuzSocketInfo != NULL)
				{
					if(uuid_compare(juzSendInfo.uu,JuzSocketInfo->uu) == 0)//uuid 相同
					{
						if(pthread_mutex_trylock(JuzSocketInfo->mMutex) == 0)
						{
							isSendState = true;
						}
						else
						{
							isMutex = true;
						}
					}
					else
					{
						char out[32];
						char dst[32];
						uuid_unparse(JuzSocketInfo->uu,out);
						uuid_unparse(juzSendInfo.uu,dst);

						JuzLog::LogA(4,"UUID不相等 uuid1:%s uuid2:%s",out,dst);
					}
				}
			};

			netMain->mAllClientInfo.find_fn(nSocketFD,findStatePro);

			if(isSendState)//需要发送
			{
				char *sendData = sendEv->getSendData();
				if(sendData != NULL)
				{
					int nSendLenCount = sendEv->getLen();
					JuzLog::LogA(4,"准备发送数据 fd:%d 长度:%d",sendEv->getNfd(),nSendLenCount);

					int nSendCount = 0;
					while(true)
					{
						int nRecv = send(nSocketFD,sendData + nSendCount,nSendLenCount - nSendCount,0);
						if(nRecv > 0)
						{
							nSendCount += nRecv;
							if(nSendCount == nSendLenCount) //发送完成
							{
								nFinshState = 1;
								break;
							}
						}
						else
						{
							if(nRecv < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN))
							{
								continue;
							}
							else
							{
								break;
							}
						}
					}
				}

				//需要解锁
				netMain->mAllClientInfo.find_fn(nSocketFD,[&](const JUZ_TBB_DATA& JuzTbbData){
					JUZ_EPOLL_CLIEN *JuzSocketInfo = NULL;
					JuzSocketInfo = JuzTbbData.mTo;

					if(JuzSocketInfo != NULL)
					{
						pthread_mutex_unlock(JuzSocketInfo->mMutex);
					}
				});
			}

			if(isMutex) //如果是互斥
			{
				//弹回去 信号++
				if(netMain->mSendList.enqueue(juzSendInfo))
				{
					sem_post(netMain->send_sem);
				}
			}
			else
			{
				JuzLog::LogA(4,"发送完成 fd:%d 状态码:%d",sendEv->getNfd(),nFinshState);

				sendEv->finsh(nFinshState);
				delete sendEv;
			}

		}
	}
	return NULL;
}
void* NetWorkMain::socketJuzAccept(void *args)
{
	int nClienFd = -1;
	if(args != NULL)
	{
		int listenfd = *((int*)(args));
		if(listenfd != -1)
		{
			struct sockaddr_in cliaddr;
			socklen_t socklen = sizeof(struct sockaddr_in);
			while(1)
			{
				nClienFd = accept(g_Serverlistenfd,(struct sockaddr *)&cliaddr,&socklen);
				if(nClienFd > 0)
				{
					int port = cliaddr.sin_port;
					in_addr_t clientIp = cliaddr.sin_addr.s_addr;

					JUZ_EPOLL_CLIEN *jEpollClient = new JUZ_EPOLL_CLIEN;

					JUZ_TBB_DATA jbData;
					jbData.mTo = jEpollClient;

					JuzLog::LogA(4,"accept fd:%d",nClienFd);

					if(NetWorkMain::getInstance()->mAllClientInfo.insert(nClienFd,jbData))
					{
						//cout<<"accept12"<<endl;
						jEpollClient->mPort = port;
						strcpy(jEpollClient->mIp,inet_ntoa(*((struct in_addr*)&clientIp)));

						setAttribute(nClienFd,true);//添加到监控列表

						//添加到tcp监控
						TcpCheckJuzEvent *tcpEvent = new TcpCheckJuzEvent(nClienFd,1);//1 = create
						TaskJuzEvent *taskEv = new TaskJuzEvent();
						taskEv->setWhat(2);//发送事件
						taskEv->setArg1(tcpEvent);
						NetWorkMain::getInstance()->sendEvent(taskEv);

						JuzLog::LogA(4,"accept IP地址:%s 端口:%d  fd = %d",inet_ntoa(*((struct in_addr*)&clientIp)),port,nClienFd);
					}
					else
					{
						delete jEpollClient;
						close(nClienFd);
						JuzLog::LogStr("accept 强制关闭");
					}
				}
				else
				{
					JuzLog::LogA(1,"服务器 accept 失败 :%d 原因:%s",nClienFd,strerror(errno));
				}
			}
		}
	}

	return NULL;
}
bool NetWorkMain::RC4_SOCKET(char *key,int nLen,char *src,char *out)
{
	bool bResult = false;
	if(key != NULL && src != NULL && out != NULL)
	{
		char nowKey[32];
		int nKeyLen = sizeof(nowKey);
		memset(nowKey,0,nKeyLen);
		strcpy(nowKey,key);

		RC4_KEY  rc4Key;
		RC4_set_key(&rc4Key,nKeyLen, (unsigned char*)nowKey);
		RC4(&rc4Key, nLen, (unsigned char*)src, (unsigned char*)out);

		bResult = true;
	}

	return bResult;
}
int NetWorkMain::decryptedDataInfo(char *key,JUZ_SOCKET_DATA &sockData)
{
	// -1.头部校验失败  -2.不是规定的数据 -3 解密失败
	// １　成功
	int nDataLen = sizeof(JUZ_SOCKET_DATA);
	char *pOutData = new char[nDataLen];
	memset(pOutData,0,nDataLen);

//	//１．解密数据
	if(!NetWorkMain::RC4_SOCKET(key,nDataLen,(char*)&sockData,pOutData))
	{
		delete[] pOutData;
		return -3;
	};

	//２．数据排列验证
	for(int i = 0 ; i < nDataLen ; i += 2)
	{
		if((i + 1) < nDataLen) //不要越界了
		{
			//交换
			char swap;
			swap = *(pOutData + i);
			*(pOutData + i) = *(pOutData + i + 1);   // 1 = 2
			*(pOutData + i + 1) = swap;     // 2 = 1
		}
	}

	memcpy(&sockData,pOutData,nDataLen); //copy到原始
	delete[] pOutData;

	//校验　ｓｕｍ
	char newSum = (sockData.nLen & 0xff) + sockData.what + sockData.type + sockData.arg1 + sockData.arg2;
	if(newSum != sockData.sum)
	{
		return -1;
	}

	//３．验证是否是规定数据
	bool isYesv = false;
	for(int i = 0 ; i < ARRSIZE(g_socketVaRecv) ;i++)
	{
		if(g_socketVaRecv[i].isCmp(sockData.what,sockData.type,sockData.arg1,sockData.arg2))
		{
			isYesv = true;
			break;
		}
	}

	if(!isYesv)
	{
		return -2;
	}


	return 1;
}
void* NetWorkMain::socketRecv(void* args) {
	static int nThreadNum = 0;
	nThreadNum++;
	int nTheThreadNum = nThreadNum;
	NetWorkMain *netMain = NetWorkMain::getInstance();
	while(true)
	{
		sem_wait(netMain->recv_sem); //如果有 准备好的recv
		int fd = -1;
		if(netMain->mRecvList.try_dequeue(fd) && fd != -1)
		{
			//cout<<"当前线程:"<<nTheThreadNum<<endl;

			bool IsRestore = true;//是否恢复fd的监视状态
			int nSocketfd = fd;

			SocketInfoJuzEvent *sockInfoDataJuz = NULL;
			char *keyFinsh = NULL;//key 密钥

			bool isNotFind = true;
			char recvHeadData[SOCKETHEAD] = {0};  //头部数据
			char *recvBobyData = NULL; //身体
			int nCurrentRecvCount = 0;
			char nFDKey[32] = {0};//这个ｆｄ的加密　密钥
			JUZ_SOCKET_DATA JUZHEAD;

			auto getHeadPro = [&](const JUZ_TBB_DATA& JuzTbbData){
				JUZ_EPOLL_CLIEN *JuzSocketInfo = NULL;
				JuzSocketInfo = JuzTbbData.mTo;

				if(JuzSocketInfo != NULL)
				{
					isNotFind = false;
					recvBobyData = (char*)JuzSocketInfo->mpData;
					nCurrentRecvCount = JuzSocketInfo->mCount;

					if(JuzSocketInfo->mIsencrypt) //如果有加密 使用
					{
						memcpy(nFDKey,JuzSocketInfo->mKey,strlen(JuzSocketInfo->mKey));
					}
					else
					{
						memcpy(nFDKey,g_keyDefault,strlen(g_keyDefault));
					}

					if(nCurrentRecvCount <= 0)
					{
						JuzSocketInfo->mCount = 0;
						memset(&JuzSocketInfo->mJSD,0,SOCKETHEAD);
					}
					else
					{
						memcpy(recvHeadData,&JuzSocketInfo->mJSD ,SOCKETHEAD);
					}
				}
			};

			if(netMain->mAllClientInfo.find_fn(nSocketfd,getHeadPro) && !isNotFind)
			{
				bool IsRecvData = true; //是否接收真实数据
				//1.确保协议头接受完毕
				if(nCurrentRecvCount < SOCKETHEAD)
				{
					bool bAcharmNot = false; //校验是否失败
					while(true)
					{
						int recvNum = recv(fd,recvHeadData + nCurrentRecvCount,SOCKETHEAD - nCurrentRecvCount,0);

						if(recvNum > 0) //成功读到数据
						{
							JuzLog::LogA(3,"接受量:%d",recvNum);

							nCurrentRecvCount += recvNum;

							if(nCurrentRecvCount  == SOCKETHEAD)//接受完成
							{
								int nError = netMain->decryptedDataInfo(nFDKey,*((JUZ_SOCKET_DATA*)recvHeadData));//数据解密　＋　验证
								if(nError < 0) //校验失败
								{
									JuzLog::LogA(3,"校验失败!进行关闭socket id =:%d,错误原因：%d 密钥为:%s",fd,nError,nFDKey);

									IsRestore = false;
									IsRecvData = false;
									bAcharmNot = true;
								}
								break;
							}
						}
						else if(recvNum < 0 && (errno == EAGAIN || errno == EAGAIN || errno == EWOULDBLOCK )) //客户端读不到数据了
						{
							IsRecvData = false; //连接读断了,不要试图去接受　真实数据
							break;
						}
						else if(recvNum == 0 || recvNum < 0) //客户端 关闭
						{
							//发送　退出事件
							NetWorkMain::SendClientQUitEv(fd,recvNum);

							IsRestore = false;
							IsRecvData = false; //连接读断了,不要试图去接受　真实数据
							break;
						}
					}
					if(bAcharmNot) //头部验证不通过
					{
						NetWorkMain::SendClientQUitEv(fd,-100);
					}
				}

				//2.接受真实数据
				if(IsRecvData) //接受真的数据
				{
					JUZHEAD = *((JUZ_SOCKET_DATA*)recvHeadData);

					int nReadyNum = JUZHEAD.nLen - nCurrentRecvCount; //总长度　－　已接收长度
					if(nReadyNum > 0)
					{
						int nDataLen = JUZHEAD.nLen - SOCKETHEAD; //真实数据长
						if(recvBobyData == NULL)
						{
							recvBobyData  = new char[nDataLen];
						}

						int recvNum  = 0;
						char *StoredAlloc = (char*)recvBobyData;  //存放的地方
						while(true)
						{
							nReadyNum = JUZHEAD.nLen - nCurrentRecvCount;
							recvNum = recv(fd,StoredAlloc + (nDataLen - nReadyNum),nReadyNum,0);

							if(recvNum > 0) //成功读到数据
							{
								nCurrentRecvCount += recvNum;

								if(nCurrentRecvCount  == JUZHEAD.nLen) //接受完成
								{
									break;
								}
							}
							else if(recvNum < 0 && (errno == EAGAIN || errno == EAGAIN || errno == EWOULDBLOCK )) //客户端读不到数据了
							{
								break;
							}
							else if(recvNum == 0 || recvNum < 0) //客户端自己关闭
							{
								IsRestore = false;
								NetWorkMain::SendClientQUitEv(fd,recvNum);
								break;
							}
						}
					}
				}

				//把数据拷贝回去

				//３．判断数据是否完成!
				if(IsRestore && IsRecvData) //期间客户没有断线
				{
					if(nCurrentRecvCount  >= JUZHEAD.nLen)
					{
						//推送事件
						sockInfoDataJuz = new SocketInfoJuzEvent(fd,JUZHEAD.what,JUZHEAD.type,JUZHEAD.arg1,JUZHEAD.arg2,JUZHEAD.nLen,recvBobyData);

						keyFinsh = new char[32];
						memset(keyFinsh,0,sizeof(char) * 32);
						strcpy(keyFinsh,nFDKey);
						JuzLog::LogA(3,"接受数据完成　推辞送事件：what:%d type:%d arg1:%d arg2:%d nLen:%d",JUZHEAD.what,JUZHEAD.type,JUZHEAD.arg1,JUZHEAD.arg2,JUZHEAD.nLen);;

						//初始化
						recvBobyData = NULL;
						nCurrentRecvCount = 0;
					}
				}

				//初始化
				netMain->mAllClientInfo.update_fn(nSocketfd,[&](JUZ_TBB_DATA&JuzTbbData){
					JUZ_EPOLL_CLIEN *JuzSocketInfo = NULL;
					JuzSocketInfo = JuzTbbData.mTo;
					if(JuzSocketInfo != NULL)
					{
						isNotFind = false;
						JuzSocketInfo->mCount = nCurrentRecvCount;
						JuzSocketInfo->mpData = recvBobyData;
						JuzSocketInfo->mJSD = JUZHEAD;
					}
				});

			}

			if(isNotFind)
			{
				JuzLog::LogStr("完了　value是找到了,可是是空的　或者是无效的!",1);
				IsRestore = false;

				NetWorkMain::SendClientQUitEv(fd,-1);
			}

			if(sockInfoDataJuz != NULL)
			{
				if(NetWorkMain::decryptSocketData(sockInfoDataJuz,keyFinsh))
				{
					TaskJuzEvent *taskEv = new TaskJuzEvent();
					taskEv->setWhat(2);//发送事件
					taskEv->setArg1(sockInfoDataJuz);
					netMain->sendEvent(taskEv);
				}
				else
				{
					delete sockInfoDataJuz;
				}
				delete[] keyFinsh;
				keyFinsh = NULL;
			}

			if(IsRestore) //恢复
			{
				setAttribute(fd,false);
			}
			else
			{
				JuzLog::LogStr("IsRestore 不恢复",1);
				netMain->closeSocket_Juz(fd);
			}
		}
		else
		{
			if(netMain->mRecvList.size_approx() > 0) //如果内部还有数据
			{
				sem_post(NetWorkMain::getInstance()->recv_sem);
			}
			JuzLog::LogStr("socketRecv 接受线程 出大问题了! try_dequeue 弹出失败",1);
		}
	}
	return NULL;
}

void NetWorkMain::SendClientQUitEv(int nfd,int nState)
{
	//发送　退出事件
	JuzLog::LogA(3,"SendClientQUitEv:%d state :%d",nfd,nState);

	ClientQuitJuzEvent *clQuitEv = new ClientQuitJuzEvent(nfd,nState);
	TaskJuzEvent *taskEv = new TaskJuzEvent();
	taskEv->setWhat(2);//发送事件
	taskEv->setArg1(clQuitEv);
	NetWorkMain::getInstance()->sendEvent(taskEv);
}
bool NetWorkMain::decryptSocketData(SocketInfoJuzEvent *sock,char *key )
{
	bool bResult = true;
	int nLen = sock->getLen();
	char what = sock->getWhat();
	char type = sock->getType();
	char arg1 = sock->getArg1();
	char arg2 = sock->getArg2();
	char *pData = sock->getData();
	int nDataLen = nLen - SOCKETHEAD;
	char *outData = new char[nDataLen];


	if(what == 0x01 && type == 0x01)//请求分配密钥
	{
		bResult = false;
		if (NetWorkMain::RC4_SOCKET(key, nDataLen, pData, outData)) {
			JUZVERSION *ver = (JUZVERSION*)outData;

			if((ver->type == 0x02 && ver->version == NetWorkMain::UNITEVERMCSERVER) ||
					(ver->type == 0x01 && ver->version == NetWorkMain::UNITEVERMANDROID)) //版本验证
			{
				if(socket_set_keepalive(sock->getNfd()) != -1)//心跳包
				{
					JuzLog::LogA(3,"加密完成:%d",sock->getNfd());

					int keyLen = 32;
					char *strKey = new char[keyLen]; //由完成函数delete
					memset(strKey, 0, keyLen);
					NetWorkMain::randKey(strKey, 31);

					NetWorkMain::getInstance()->mAllClientInfo.update_fn(sock->getNfd(),[&](JUZ_TBB_DATA &JuzTbbData){
						JUZ_EPOLL_CLIEN *JuzSocketInfo = NULL;
						JuzSocketInfo = JuzTbbData.mTo;

						if(JuzSocketInfo != NULL)
						{
							//生产唯一识别
							uuid_generate(JuzSocketInfo->uu);
						}
					});

					//复制到链表
					auto upDataPro = [&](JUZ_TBB_DATA &JuzTbbData) {
						JUZ_EPOLL_CLIEN *JuzSocketInfo = NULL;
						JuzSocketInfo = JuzTbbData.mTo;
						if(JuzSocketInfo != NULL)
						{
							memset(JuzSocketInfo->mKey,0,sizeof(JuzSocketInfo->mKey));
							strcpy(JuzSocketInfo->mKey,strKey);
							JuzSocketInfo->mIsencrypt = true;
						}
					};
					SendSocketJuzEvent *sendKey = new SendSocketJuzEvent(
							sock->getNfd(), 0x01, 0x01, 0x01, 0x00, keyLen,
							strKey);
					sendKey->setPublicEncryption();
					NetWorkMain::getInstance()->sendEvent(sendKey);

					//在加完密后
					NetWorkMain::getInstance()->mAllClientInfo.update_fn(sock->getNfd(),upDataPro);

					delete[] strKey;
				}
			}
		}
		char *pDelData = pData;
		delete[] pDelData;
	}
	else
	{
		if (NetWorkMain::RC4_SOCKET(key, nDataLen, pData, outData)) {
			memcpy(pData, outData, nDataLen);
		}
	}

	delete[] outData;

	return bResult;
}
void NetWorkMain::closeSocket_Juz(int fd)
{
	if(fd > 0)
	{
		 epoll_event event;
		 event.data.fd = fd;
		 event.events = EPOLLIN | EPOLLONESHOT;

		 epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, &event);
	}
}
void NetWorkMain::clientQuit(ClientQuitJuzEvent *clEv)
{
	int  nFd = clEv->fdSocket;

	JuzLog::LogA(3,"客户端退出:%d 原因:%d",nFd,clEv->getQuitId());

	auto delPro = [&](JUZ_TBB_DATA & JuzTbbData){
		close(nFd);//关掉客户端
		JUZ_EPOLL_CLIEN *JuzSocketInfo = NULL;

		JuzSocketInfo = JuzTbbData.mTo;
		if(JuzSocketInfo != NULL)
		{
			if(JuzSocketInfo->mpData != NULL)
			{
				char *pData = (char*)JuzSocketInfo->mpData;
				JuzSocketInfo->mpData = NULL;
				delete[] pData;
			}

			delete JuzSocketInfo;
		}

		JuzTbbData.mTo = NULL;
		return true;
	};

	//删除
	if(!mAllClientInfo.erase_fn(clEv->fdSocket,delPro))
	{
		JuzLog::LogStr("clientQuit　删除失败!");
	}
}
void NetWorkMain::OnCommand(OnCommandJuzEvent* ev)
{
	int nLen = ev->getLen();
	if(nLen == 2)
	{
		string strCommand = ev->getCommand(0);
		if(strCommand == "show")
		{
			strCommand =  ev->getCommand(1);
			if(strCommand == "fds")
			{
				JUZ_TBB_DATA JuzTbbData;
				auto  lt = mAllClientInfo.lock_table();
			    for (const auto &it : lt) {
			    	JuzTbbData = it.second;
			    	JUZ_EPOLL_CLIEN *JuzSocketInfo = JuzTbbData.mTo;
			    	if(JuzSocketInfo != NULL)
			    	{
			    		cout<<"客户端IP:"<<JuzSocketInfo->mIp<<" 端口:"<<JuzSocketInfo->mPort<<"　SocketID:"<<it.first<<endl;
			    	}
			    }
			    lt.unlock();
			}
			else if(strCommand == "size")
			{
				int size = mAllClientInfo.size();
				cout<<"目前客户端连接数:"<<size<<endl;
			}
		}
	}
}

void NetWorkMain::setAttribute(int fd, bool status)
{
	 epoll_event event;
	 memset(&event,0,sizeof(event));
	 event.data.fd = fd;
	 event.events = EPOLLIN | EPOLLONESHOT;
	 if(status) //add
	 {
		 int old_option = fcntl(fd, F_GETFL);
		 int new_option = old_option | O_NONBLOCK;
		 fcntl(fd, F_SETFL, new_option);

		 epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &event);
	 }
	 else //mod
	 {
		 epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, &event);
	 }
}
void* NetWorkMain::socketWaitData(void* args)
{
	if(mEpollFd == -1) return NULL;
	static const int WAIT_COUNT = 10000;
	epoll_event events[WAIT_COUNT];

	static int nThreadNum = 0;
	nThreadNum++;
	int nCurrentTHreadNum = nThreadNum;

	int nCount = 0;

	while(true)
	{
		nCount = epoll_wait(mEpollFd, events, WAIT_COUNT, -1);
		for(int i = 0 ; i < nCount; ++i)
		{
			if( events[i].events & EPOLLIN) //有数据
			{
			//	cout<<"wait当前线程:"<<nCurrentTHreadNum<<endl;
				NetWorkMain::getInstance()->mRecvList.enqueue(events[i].data.fd);
				sem_post(NetWorkMain::getInstance()->recv_sem);
			}
			else
			{
				NetWorkMain::SendClientQUitEv(events[i].data.fd,-200);
			}
		}
		if(nCount <= 0)
		{
			JuzLog::LogStr("epoll_wait 数据失败!");
		}
	}

	return NULL;
}




